package com.margo.project.retry.service;

import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import com.margo.project.retry.exception.MargoRetryException;

/**
 * https://www.jianshu.com/p/58e753ca0151
 * 
 * @Retryable 标注此注解的方法在发生异常时会进行重试
 * value：指定处理的异常类
 * include：指定处理的异常类和value一样，默认为空，当exclude也为空时，默认所有异常
 * exclude：指定异常不处理，默认空，当include也为空时，默认所有异常
 * maxAttempts：最大重试次数。默认3次
 * -backoff： 重试补偿策略。默认使用@Backoff注解
 * 
 *	@Backoff 重试补偿策略
 *	不设置参数时，默认使用FixedBackOffPolicy（指定等待时间），重试等待1000ms
 *	设置delay,使用FixedBackOffPolicy（指定等待- - 设置delay和maxDealy时，重试等待在这两个值之间均态分布
 *	设置delay、maxDealy、multiplier，使用 ExponentialBackOffPolicy（指数级重试间隔的实现 ），multiplier即指定延迟倍数，
 *	比如delay=5000l,multiplier=2,则第一次重试为5秒，第二次为10秒，第三次为20秒
 *
 * @Recover 用于@Retryable重试失败后处理方法，此注解注释的方法参数一定要是@Retryable抛出的异常，否则无法识别，
 * 	可以在该方法中进行日志处理。
 * @author fangxingbang
 *
 */
@Service
public class MargoRetryService {
	
	private Logger logger=LoggerFactory.getLogger(MargoRetryService.class);
	
	private AtomicInteger intRetry=new AtomicInteger(0);

	//指定，重试5次，每次补偿(延迟5秒)，每次倍数为1（不变）
	@Retryable(backoff = @Backoff(delay = 5000l,multiplier = 1),listeners= {"margoRetryListener"})
	public void sendMsg() {
		//重试三次以后抛出异常
		if(intRetry.incrementAndGet()<10) {
			logger.info("需要重试:"+intRetry.get());
			throw new RuntimeException();
		}
		intRetry.set(0);
		logger.info("调用成功");
	}
	
	@Retryable(value=MargoRetryException.class)
	public void sendExceptionMsg() throws MargoRetryException {
		//直接抛出异常
		if(intRetry.incrementAndGet()<3) {
			logger.info("需要重试:"+intRetry.get());
			throw new MargoRetryException();
		}
		intRetry.set(0);
		logger.info("调用成功");
	}
	
	@Recover	
	public void recover(RuntimeException e) {
		logger.info("执行这里的");
	}
}
